package com.sykj.seaflow.sys.modual.menu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sykj.seaflow.common.base.bean.PageQuery;
import com.sykj.seaflow.common.base.exception.CommonException;
import com.sykj.seaflow.common.base.util.LoginHelper;
import com.sykj.seaflow.sys.modual.identifier.entity.SysIdentifier;
import com.sykj.seaflow.sys.modual.identifier.service.SysIdentifierService;
import com.sykj.seaflow.sys.modual.menu.entity.SysMenu;
import com.sykj.seaflow.sys.modual.menu.mapper.SysMenuMapper;
import com.sykj.seaflow.sys.modual.menu.params.SysMenuAddParam;
import com.sykj.seaflow.sys.modual.menu.params.SysMenuEditParam;
import com.sykj.seaflow.sys.modual.menu.params.SysMenuIdParam;
import com.sykj.seaflow.sys.modual.menu.params.SysMenuPageParam;
import com.sykj.seaflow.sys.modual.menu.service.SysMenuService;
import com.sykj.seaflow.sys.modual.resource.enums.ResourceType;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@AllArgsConstructor
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    private final SysIdentifierService identifierService;

    @Override
    public void add(SysMenuAddParam sysMenuAddParam) {
        SysMenu sysMenu = BeanUtil.copyProperties(sysMenuAddParam, SysMenu.class);
        this.save(sysMenu);
    }

    @Override
    public void edit(SysMenuEditParam sysMenuEditParam) {
        SysMenu sysMenu = BeanUtil.copyProperties(sysMenuEditParam, SysMenu.class);
        this.updateById(sysMenu);
    }

    @Override
    public IPage<SysMenu> page(SysMenuPageParam sysMenuPageParam, PageQuery<SysMenu> pageQuery) {
        QueryWrapper<SysMenu> query = buildQueryWrapper(sysMenuPageParam);
        return this.getBaseMapper().selectPage(pageQuery.getPage(), query);
    }

    private QueryWrapper<SysMenu> buildQueryWrapper(SysMenuPageParam sysMenuPageParam) {
        QueryWrapper<SysMenu> query = Wrappers.query();
        query.lambda().eq(ObjectUtil.isNotEmpty(sysMenuPageParam.getName()), SysMenu::getName, sysMenuPageParam.getName());
        return query;
    }


    @Override
    public SysMenu detail(SysMenuIdParam sysMenuIdParam) {
        return this.getById(sysMenuIdParam.getId());
    }

    @Transactional
    @Override
    public void deletes(List<SysMenuIdParam> ids) {
        List<Long> list = CollStreamUtil.toList(ids, SysMenuIdParam::getId);
        long count = this.count(Wrappers.<SysMenu>lambdaQuery().in(SysMenu::getParentId, list));
        if(count > 0){
            throw new CommonException("请先删除下级菜单");
        }
        this.removeBatchByIds(list);
    }

    @Override
    public void delete(SysMenuIdParam sysMenuIdParam) {
        this.removeById(sysMenuIdParam.getId());
    }

    @Override
    public List<Tree<String>> tree(SysMenuPageParam sysMenuPageParam) {
        List<SysMenu> list = this.userMenus();
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 都有默认值的
        treeNodeConfig.setWeightKey("sortNum");
        List<Tree<String>> treeNodes = TreeUtil.<SysMenu, String>build(list, "0", treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(String.valueOf(treeNode.getId()));
                    tree.setParentId(String.valueOf(treeNode.getParentId()));
                    tree.setWeight(treeNode.getSortNum());
                    tree.setName(treeNode.getName());
                    tree.putExtra("path", treeNode.getPath());
                    tree.putExtra("component", treeNode.getComponent());
                    tree.putExtra("params", treeNode.getParams());
                    tree.putExtra("status", treeNode.getStatus());
                    tree.putExtra("type", treeNode.getType());
                    tree.putExtra("type", treeNode.getType());
                    tree.putExtra("icon", treeNode.getIcon());
                });
        return treeNodes;
    }

    private List<SysMenu> userMenus() {
        Long userId = LoginHelper.getUserId();
//        WHERE roleUser.user_id = 1 OR positionUser.user_id = 1 OR USER.id = 1
        QueryWrapper<Object> query = Wrappers.query();
        query.and(wrapper -> wrapper.eq("roleUser.user_id", userId).or()
                .eq("positionUser.user_id", userId).or()
                .eq("user.id",userId));
        query.eq("resource.resource_type", ResourceType.menu.getValue());
        return this.getBaseMapper().selectMenus(query);
    }

    @Override
    public List<Tree<String>> allMenus() {
        List<SysMenu> menus = this.list();
        List<SysIdentifier> identifiers = identifierService.list();
        Map<Long, List<SysIdentifier>>  listMap = CollStreamUtil.groupByKey(identifiers, SysIdentifier::getMenuId);
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 都有默认值的
        treeNodeConfig.setWeightKey("sortNum");
        List<Tree<String>> treeNodes = TreeUtil.<SysMenu, String>build(menus, "0", treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(String.valueOf(treeNode.getId()));
                    tree.setParentId(String.valueOf(treeNode.getParentId()));
                    tree.setWeight(treeNode.getSortNum());
                    tree.setName(treeNode.getName());
                    tree.putExtra("path", treeNode.getPath());
                    tree.putExtra("component", treeNode.getComponent());
                    tree.putExtra("params", treeNode.getParams());
                    tree.putExtra("status", treeNode.getStatus());
                    tree.putExtra("type", treeNode.getType());
                    tree.putExtra("icon", treeNode.getIcon());
                    tree.putExtra("resourceType", "1");

                    List<SysIdentifier> identifiersList = listMap.get(treeNode.getId());
                    if(ObjectUtil.isNotEmpty(identifiersList)){
                        tree.putExtra("isPenultimate", true);
                        for(SysIdentifier identifier : identifiersList){
                            Tree<String> child = new Tree<>();
                            child.setWeight(identifier.getSortNum());
                            child.setName(identifier.getName());
                            child.setId(String.valueOf(identifier.getId()));
                            child.setParentId(String.valueOf(treeNode.getId()));
                            child.putExtra("type", "button");
                            child.putExtra("isButton", true);
                            child.putExtra("resourceType", "2");
                            tree.addChildren(child);
                        }

                    }
                });
        renderParent(treeNodes);
        return treeNodes;
    }

    private void renderParent(List<Tree<String>> treeNodes) {
        if(treeNodes != null && treeNodes.size() >= 0){
            for(Tree<String> treeNode : treeNodes){
                Tree<String> parent = treeNode.getParent();
                if(parent != null){
                    Tree tree2 = BeanUtil.copyProperties(parent, Tree.class);
                    tree2.setChildren(null);
                    treeNode.setParent(tree2);
                    treeNode.putExtra("parent", tree2);
                }
                if(treeNode.getChildren() != null){
                    renderParent( treeNode.getChildren());
                }

            }
        }

    }
}
